package a.a;

import java.util.HashMap;

import android.content.Context;
import android.database.DataSetObserver;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListAdapter;
import android.widget.ListView;

public class SwapableListView extends ListView {
	private static final String TAG = "SwapableListView";
	private SwapableAdapter mAdapter;
	private OnItemSwappedListener mOnItemSwapListener;

	public interface OnItemSwappedListener {
		void onItemSwapped(ListView l, Object item1, Object item2);
	}

	public SwapableListView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}

	public SwapableListView(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	public SwapableListView(Context context) {
		super(context);
	}

	@Override
	public void setAdapter(ListAdapter adapter) {
		mAdapter = new SwapableAdapter(adapter);
		super.setAdapter(mAdapter);
	}

	@Override
	public ListAdapter getAdapter() {
		if (mAdapter != null) {
			return mAdapter.mAdapter;
		}
		return super.getAdapter();
	}

	@Override
	protected void onDetachedFromWindow() {
		super.onDetachedFromWindow();
		mAdapter.reset();
	}

	@Override
	public long getItemIdAtPosition(int position) {
		return mAdapter.getItemId(position);
	}

	@Override
	public Object getItemAtPosition(int position) {
		return mAdapter.getItem(position);
	}

	public void swapPositioin(int position, int swapPosition) {
		if (position < 0 || getCount() <= position || swapPosition < 0 || getCount() <= swapPosition) {
			throw new IllegalArgumentException("Positions out of bounds:position=" + position + ", swapPosition=" + swapPosition);
		}

		mAdapter.swapPosition(position, swapPosition);
		mAdapter.notifyDataSetChanged();
		if (mOnItemSwapListener != null) {
			mOnItemSwapListener.onItemSwapped(this, mAdapter.getItem(swapPosition), mAdapter.getItem(position));
		}
	}

	public void setOnItemSwapListener(OnItemSwappedListener l) {
		mOnItemSwapListener = l;
	}

	/**
	 *
	 */
	private class SwapableAdapter extends BaseAdapter {
		private ListAdapter mAdapter;
		private HashMap<Integer, Integer> mSwapPositions;

		private SwapableAdapter(ListAdapter adapter) {
			mAdapter = adapter;
			mSwapPositions = new HashMap<Integer, Integer>();
		}

		private void swapPosition(int position, int swapPosition) {

			int pos = replace(position);
			int swap = replace(swapPosition);

			mSwapPositions.put(position, swap);
			mSwapPositions.put(swapPosition, pos);

			if (mSwapPositions.get(position).equals(position)) {
				mSwapPositions.remove(position);
			}

			if (mSwapPositions.get(swapPosition).equals(swapPosition)) {
				mSwapPositions.remove(swapPosition);
			}
		}

		private int replace(int position) {
			if (mSwapPositions.containsKey(position)) {
				return mSwapPositions.get(position);
			}
			return position;
		}

		private void reset() {
			mSwapPositions.clear();
		}

		@Override
		public int getCount() {
			return mAdapter.getCount();
		}

		@Override
		public Object getItem(int position) {
			return mAdapter.getItem(replace(position));
		}

		@Override
		public long getItemId(int position) {
			return mAdapter.getItemId(replace(position));
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			return mAdapter.getView(replace(position), convertView, parent);
		}

		@Override
		public boolean hasStableIds() {
			return true;
		}

		@Override
		public void registerDataSetObserver(DataSetObserver observer) {
			mAdapter.registerDataSetObserver(observer);
		}

		@Override
		public void unregisterDataSetObserver(DataSetObserver observer) {
			mAdapter.unregisterDataSetObserver(observer);
		}

		@Override
		public void notifyDataSetChanged() {
			if (mAdapter instanceof BaseAdapter) {
				((BaseAdapter) mAdapter).notifyDataSetChanged();
			}
		}

		@Override
		public void notifyDataSetInvalidated() {
			if (mAdapter instanceof BaseAdapter) {
				((BaseAdapter) mAdapter).notifyDataSetInvalidated();
			}
		}

		@Override
		public boolean areAllItemsEnabled() {
			return mAdapter.areAllItemsEnabled();
		}

		@Override
		public boolean isEnabled(int position) {
			return mAdapter.isEnabled(position);
		}

		@Override
		public View getDropDownView(int position, View convertView, ViewGroup parent) {
			if (mAdapter instanceof BaseAdapter) {
				return ((BaseAdapter) mAdapter).getDropDownView(replace(position), convertView, parent);
			}
			throw new UnsupportedOperationException();
		}

		@Override
		public int getItemViewType(int position) {
			return mAdapter.getItemViewType(position);
		}

		@Override
		public int getViewTypeCount() {
			return mAdapter.getViewTypeCount();
		}

		@Override
		public boolean isEmpty() {
			return mAdapter.isEmpty();
		}
	}
}
